package com.yy.micro.magic.core.filter;

import com.yy.micro.magic.core.domain.MagicRequest;
import com.yy.micro.magic.core.model.ResultCollector;
import com.yy.micro.magic.core.model.RuleDescriptor;
import com.yy.micro.magic.core.model.RuleKey;
import com.yy.micro.magic.core.model.RuntimeMetadata;
import com.yy.micro.magic.core.strategy.RuleStrategy;
import com.yy.micro.magic.exception.MapException;
import com.yy.micro.magic.ext.domain.filter.DynamicTrigger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.List;
 /**
   * @author YY
   * @version 1.0.0
   * @update 2021/9/20 9:54 下午
   * @description: 动态规则过滤的抽象基类，设定了动态规则匹配的模式。
 */
public abstract class DynamicRuleMagicFilter implements MagicFilter {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    protected MagicRequest request;

    protected RuntimeMetadata metadata;

    protected ResultCollector collector;

    protected DynamicTrigger condition;


    @Override
    public void doFilter(final RuntimeMetadata metadata, final ResultCollector collector,
                         final FilterChain filterChain) {
        this.request = metadata.getRequest();
        this.metadata = metadata;
        this.collector = collector;
        doInternalFilter(filterChain,metadata);
    }

    protected  void doInternalFilter(FilterChain filterChain,RuntimeMetadata metadata){
        String[] patterns = getRulePatterns(metadata);
        if (null != patterns && patterns.length >0){
            Arrays.stream(patterns).forEach(p->{
                execute(metadata, p);
            });
        }
    }

    /**
     * 执行动态规则，根据正则从已定义的PlanSchedule中过滤出动态Rule，并执行。
     * @param metadata 运行时数据
     * @param pattern 正则过滤出符合条件的动态Rule
     */
    protected void execute(final RuntimeMetadata metadata, final String pattern) {
        List<RuleDescriptor> rules=this.request.getSchedule().findDynamicRules(pattern);
        if (!CollectionUtils.isEmpty(rules)){
            rules.forEach(r->{
                RuleDescriptor rule = r.copy();
                this.resetRuleInput(rule, metadata.getRuleKey());//重置Rule的Input
                this.resetRuleOutput(rule, metadata.getRuleKey());
                RuntimeMetadata runtimeMetadata = metadata.clone();
                runtimeMetadata.setRule(rule);
                execute(runtimeMetadata);
            });
        }
    }

    protected String[] getRulePatterns(RuntimeMetadata metadata){
        DynamicTrigger condition = getTrigger(metadata);
        if (null != condition){
            return condition.getPatterns();
        }
        return null;
    }

    public DynamicTrigger getTrigger(RuntimeMetadata metadata){
        return null;
    }

     /**
      * 根据当前源数据节点，动态修改变换规则中取值路径。
      * @param rule  变换规则{@link RuleDescriptor}
      * @param key 当前源数据的数据节点{@link RuleKey}
      */
    protected void resetRuleInput(RuleDescriptor rule, RuleKey key){
        resetRuleInput(rule,key,true);
    }

     /**
      * 重置{@link RuleDescriptor}的Input地址。
      * @param rule {@link RuleDescriptor}
      * @param key {@link RuleKey} 源数据当前节点的地址。
      * @param ignoreParent  重围Input地址时，是否忽略叶子节点前的父地址。默认true。
      */
    protected void resetRuleInput(RuleDescriptor rule, RuleKey key, boolean ignoreParent){
        String input = rule.getInput();
        if (!StringUtils.isEmpty(input)){
            RuleKey inputKey = RuleKey.create(input);
            if (ignoreParent || inputKey.equalsPath(key,true)){
                RuleKey newInput = key.resetName(inputKey.getName());
                rule.setInput(newInput.getKey());
            }
        }
    }

     /**
      * 重置{@link RuleDescriptor}的Output地址，value在最终结果集中的地址。
      * @param rule {@link RuleDescriptor}
      * @param key {@link RuleKey} {@link RuleDescriptor}中的Key，结果保存地址。
      */
    protected void resetRuleOutput(RuleDescriptor rule,RuleKey key){
        String ruleKey=rule.getKey();
        String newKey = collector.generateGlobalKey(ruleKey);
        if (rule.isSyncParent()){//多重List结构时，是否更新父层List的下标
            RuleKey newRuleKey = RuleKey.create(newKey);
            newRuleKey.syncKeySequence(key);
            newKey = newRuleKey.getKey();
        }
        if (!StringUtils.isEmpty(newKey)){
            rule.setKey(newKey);
            rule.setOutput(newKey);
        }
    }

     /**
      * 执行动态变换规则
      * @param metadata
      */
    protected void execute(RuntimeMetadata metadata){
       RuleStrategy strategy =request.getContext().getComponentManager().getRuleStrategy(metadata.getRule().getStrategy());
       if (null != strategy && strategy.support(metadata)){
           strategy.process(metadata,metadata.getCollector());
       }else{
           throw new MapException("Can not find rule strategy "+metadata.getStrategy());
       }
    }


    public void setCondition(final DynamicTrigger condition) {
        this.condition = condition;
    }
}
